es6
的出现对产出高质量的代码提供了莫大的帮助,自己用 es6
也已经有一年多的时间了,最近重新再看一遍阮老师的 es6 入门, 总觉一些个人认为比较值得书写笔记的知识点。
let 和 const
暂时性死区 TDZ
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
1 | if (true) { |
上面代码中,在let命令声明变量tmp之前,都属于变量tmp的“死区”。
“暂时性死区”也意味着typeof不再是一个百分之百安全的操作。
1 | typeof x; // ReferenceError |
在没有let之前,typeof运算符是百分之百安全的,永远不会报错。现在这一点不成立了。这样的设计是为了让大家养成良好的编程习惯,变量一定要在声明之后使用,否则就报错。
总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
块级作用域 与 函数声明
ES5 规定, 函数只能在顶层作用于和函数作用域之中声明,不能再块级作用域声明。1
2
3
4
5
6
7
8
9
10
11// 情况一
if (true) {
function f() {}
}
// 情况二
try {
function f() {}
} catch(e) {
// ...
}
上面两种函数声明,根据 ES5 的规定都是非法的。
但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错。
ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
但是,如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6 在附录 B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。
- 允许在块级作用域内声明函数。
- 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
- 同时,函数声明还会提升到所在的块级作用域的头部。
let
const
声明的变量不属于顶层对象
变量的解构赋值
只要某种数据结构具有 Iterator
接口,都可以采用数组形式的解构赋值
解构赋值允许指定默认值, ES6 内部使用严格相等运算符(===
),判断一个位置是否优质。所以,只有当一个数组成员严格等于 undefined
,才能生效1
2
3
4
5let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null
1 | let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; |
字符串的扩展
1 | '12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12" |
数值的扩展
Number.isFinite()
对于非数值一律返回 false
, Number.isNaN()
只有对于 NaN
才返回 true
,非 NaN
一律返回 false
。
JavaScript 内部,整数和浮点数采用的是同样的储存方法, 所以 25 和 25.0 被视为同一个值(都为整数)
1 | Number.isInteger(3.0000000000000002) // true |
由于 JavaScript 采用 IEEE 754 标准,数值存储为64位双精度格式,数值精度最多可以达到 53 个二进制位(1 个隐藏位与 52 个有效位)。如果数值的精度超过这个限度,第54位及后面的位就会被丢弃,这种情况下,Number.isInteger
可能会误判。
Number.isInteger
的参数明明不是整数,但是会返回 true
。原因就是这个小数的精度达到了小数点后16个十进制位,转成二进制位超过了53个二进制位,导致最后的那个2被丢弃了。